<template>
  <div class="slider-captcha-container">
    <div class="slider-background" ref="sliderBackground">
      <div
        class="slider-puzzle-piece"
        :style="{ left: puzzlePieceLeft + 'px', top: puzzlePieceTop + 'px' }"
      ></div>
      <div
        class="slider-puzzle-hole"
        :style="{ left: puzzleHoleLeft + 'px', top: puzzleHoleTop + 'px' }"
      ></div>
    </div>
    <div class="slider-wrapper">
      <div
        class="slider-button"
        :class="{ active: active, success: verified, error: error }"
        :style="{ left: sliderLeft + 'px' }"
        @mousedown="onSliderDown"
        @touchstart="onSliderDown"
        ref="sliderButton"
      >
        <el-icon v-if="!active && !verified && !error"><ArrowRight /></el-icon>
        <el-icon v-else-if="verified"><CircleCheck /></el-icon>
        <el-icon v-else-if="error"><CircleClose /></el-icon>
      </div>
      <div class="slider-track">
        <div
          class="slider-track-filled"
          :style="{ width: sliderLeft + 'px' }"
        ></div>
        <span class="slider-tip" v-if="!active && !verified && !error"
          >向右滑动验证</span
        >
        <span class="slider-tip success" v-else-if="verified">验证通过</span>
        <span class="slider-tip error" v-else-if="error">验证失败，请重试</span>
      </div>
    </div>
    <div v-if="loading" class="slider-loading">
      <div class="loading-spinner"></div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, computed } from "vue";
import { ArrowRight, CircleCheck, CircleClose } from "@element-plus/icons-vue";

const props = defineProps({
  // 成功偏差值，滑块左边缘距离目标位置的误差范围
  tolerance: {
    type: Number,
    default: 10,
  },
  // 重置延迟（毫秒）
  resetDelay: {
    type: Number,
    default: 1000,
  },
});

const emit = defineEmits(["success", "fail", "reset"]);

// 滑块相关
const sliderBackground = ref(null);
const sliderButton = ref(null);
const bgWidth = ref(0);
const bgHeight = ref(0);
const sliderLeft = ref(0);
const startX = ref(0);
const active = ref(false);
const verified = ref(false);
const error = ref(false);
const loading = ref(false);

// 拼图相关
const puzzlePieceSize = 40; // 拼图块大小
const puzzlePieceLeft = ref(0);
const puzzlePieceTop = ref(0);
const puzzleHoleLeft = ref(0);
const puzzleHoleTop = ref(0);

// 目标位置
const targetPosition = ref(0);

// 初始化拼图位置
function initPuzzlePosition() {
  const bgRect = sliderBackground.value.getBoundingClientRect();
  bgWidth.value = bgRect.width;
  bgHeight.value = bgRect.height;

  // 设置拼图块位置（左侧固定）
  puzzlePieceLeft.value = 30;
  puzzlePieceTop.value =
    Math.floor(Math.random() * (bgHeight.value - puzzlePieceSize - 20)) + 10;

  // 设置拼图槽位置（右侧随机）
  puzzleHoleLeft.value =
    Math.floor(Math.random() * (bgWidth.value - puzzlePieceSize - 100)) + 100;
  puzzleHoleTop.value = puzzlePieceTop.value;

  // 设置目标位置
  targetPosition.value = puzzleHoleLeft.value - puzzlePieceLeft.value;
}

// 开始滑动
function onSliderDown(e) {
  if (verified.value || loading.value) return;

  e.preventDefault();
  document.body.classList.add("no-select");
  active.value = true;
  error.value = false;

  // 记录起始位置
  startX.value = e.type === "touchstart" ? e.touches[0].clientX : e.clientX;

  // 绑定移动和释放事件
  document.addEventListener("mousemove", onSliderMove);
  document.addEventListener("touchmove", onSliderMove);
  document.addEventListener("mouseup", onSliderUp);
  document.addEventListener("touchend", onSliderUp);
}

// 滑动中
function onSliderMove(e) {
  if (!active.value) return;

  const currentX = e.type === "touchmove" ? e.touches[0].clientX : e.clientX;
  let moveX = currentX - startX.value;

  // 限制滑块在轨道内
  moveX = Math.max(0, Math.min(moveX, bgWidth.value - 40));

  sliderLeft.value = moveX;
  puzzlePieceLeft.value = 30 + moveX; // 拼图块跟随滑块移动
}

// 释放滑块
function onSliderUp() {
  if (!active.value) return;

  document.body.classList.remove("no-select");
  document.removeEventListener("mousemove", onSliderMove);
  document.removeEventListener("touchmove", onSliderMove);
  document.removeEventListener("mouseup", onSliderUp);
  document.removeEventListener("touchend", onSliderUp);

  // 验证位置
  verifyPosition();
}

// 验证位置
function verifyPosition() {
  loading.value = true;

  // 模拟验证请求延迟
  setTimeout(() => {
    loading.value = false;

    // 判断是否在目标位置附近
    const distance = Math.abs(sliderLeft.value - targetPosition.value);

    if (distance <= props.tolerance) {
      // 验证成功
      verified.value = true;
      active.value = false;
      emit("success");
    } else {
      // 验证失败
      error.value = true;
      active.value = false;
      emit("fail");

      // 延迟后重置
      setTimeout(resetSlider, props.resetDelay);
    }
  }, 500);
}

// 重置滑块
function resetSlider() {
  sliderLeft.value = 0;
  puzzlePieceLeft.value = 30;
  active.value = false;
  verified.value = false;
  error.value = false;
  initPuzzlePosition();
  emit("reset");
}

// 手动重置方法（供父组件调用）
function reset() {
  resetSlider();
}

// 暴露方法给父组件
defineExpose({
  reset,
  verified,
});

onMounted(() => {
  initPuzzlePosition();

  // 窗口大小变化时重新初始化
  window.addEventListener("resize", initPuzzlePosition);
});

onUnmounted(() => {
  window.removeEventListener("resize", initPuzzlePosition);
  document.removeEventListener("mousemove", onSliderMove);
  document.removeEventListener("touchmove", onSliderMove);
  document.removeEventListener("mouseup", onSliderUp);
  document.removeEventListener("touchend", onSliderUp);
});
</script>

<style lang="scss" scoped>
.slider-captcha-container {
  @apply flex flex-col w-full relative;

  .slider-background {
    @apply relative w-full h-40 mb-3 rounded-lg bg-gray-100 dark:bg-gray-800 overflow-hidden;
    background-image: url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 18c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm48 25c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm-43-7c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm63 31c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 90c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm56-76c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM12 86c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm28-65c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm23-11c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-6 60c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm29 22c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zM32 63c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm57-13c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-9-21c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM60 91c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM35 41c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM12 60c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z' fill='%23bfbfbf' fill-opacity='0.1' fill-rule='evenodd'/%3E%3C/svg%3E");
  }

  .slider-puzzle-piece,
  .slider-puzzle-hole {
    @apply absolute w-10 h-10 rounded-md;
  }

  .slider-puzzle-piece {
    @apply bg-blue-500 dark:bg-blue-600 shadow-md z-10;
    opacity: 0.8;
    transition: all 0.2s ease;
  }

  .slider-puzzle-hole {
    @apply border-2 border-dashed border-blue-500 dark:border-blue-400 bg-transparent;
  }

  .slider-wrapper {
    @apply relative w-full h-12 rounded-2xl bg-gray-100 dark:bg-gray-800 overflow-hidden;
  }

  .slider-button {
    @apply absolute top-1/2 transform -translate-y-1/2 z-10 
           w-10 h-10 rounded-full bg-white dark:bg-gray-700 shadow-md 
           flex items-center justify-center cursor-pointer transition-all duration-300;

    .el-icon {
      @apply text-lg;
    }

    &.active {
      @apply shadow-lg bg-blue-100 dark:bg-blue-900;
    }

    &.success {
      @apply bg-green-500 dark:bg-green-600 text-white;
    }

    &.error {
      @apply bg-red-500 dark:bg-red-600 text-white;
    }
  }

  .slider-track {
    @apply w-full h-full relative flex items-center justify-center;

    .slider-track-filled {
      @apply absolute left-0 top-0 h-full bg-blue-100 dark:bg-blue-900 transition-all duration-200;
    }

    .slider-tip {
      @apply relative z-10 text-gray-500 dark:text-gray-400 text-sm transition-all duration-300;

      &.success {
        @apply text-green-500 dark:text-green-400 font-medium;
      }

      &.error {
        @apply text-red-500 dark:text-red-400;
      }
    }
  }

  .slider-loading {
    @apply absolute inset-0 flex items-center justify-center z-20 bg-white/70 dark:bg-gray-900/70;

    .loading-spinner {
      @apply w-8 h-8 border-4 border-blue-200 dark:border-blue-900 rounded-full;
      border-top-color: #3b82f6;
      animation: spin 1s linear infinite;
    }

    @keyframes spin {
      to {
        transform: rotate(360deg);
      }
    }
  }
}

:deep(.no-select) {
  user-select: none;
  -webkit-user-select: none;
}
</style>
